﻿using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.OpenApi;
using Microsoft.Extensions.Options;
using Microsoft.OpenApi.Models;
using System.ComponentModel;
using System.Reflection;

namespace OpenApiExtensions
{

    internal sealed class BearerSecuritySchemeTransformer(IAuthenticationSchemeProvider authenticationSchemeProvider, IOptionsMonitor<OpenApiConfig> config) : IOpenApiDocumentTransformer
    {
        public async Task TransformAsync(OpenApiDocument document, OpenApiDocumentTransformerContext context, CancellationToken cancellationToken)
        {

            document.Info.Title = config.CurrentValue.Title;

            var authenticationSchemes = await authenticationSchemeProvider.GetAllSchemesAsync();
            if (authenticationSchemes.Any(authScheme => authScheme.Name == "Bearer"))
            {
                var requirements = new Dictionary<string, OpenApiSecurityScheme>
                {
                    ["Bearer"] = new OpenApiSecurityScheme
                    {
                        Type = SecuritySchemeType.Http,
                        Scheme = "bearer", // "bearer" refers to the header name here
                        In = ParameterLocation.Header,
                        BearerFormat = "Json Web Token"
                    }
                };
                document.Components ??= new OpenApiComponents();
                document.Components.SecuritySchemes = requirements;


                List<string> urls = new List<string>();
                foreach (var scheme in context.DescriptionGroups)
                {
                    if (scheme.GroupName!= context.DocumentName)
                    {
                        continue;
                    }
                    foreach (var item in scheme.Items)
                    {
                        if (item.ActionDescriptor.EndpointMetadata.Any(x => x is AuthorizeAttribute))
                        {
                            ///
                            if (!string.IsNullOrWhiteSpace(item.RelativePath))
                            {
                                urls.Add("/"+item.RelativePath);
                            }
                            else
                            {
                                var v = item.ActionDescriptor.EndpointMetadata.FirstOrDefault(x => x.GetType().Name == "RouteDiagnosticsMetadata");
                                if (v != null)
                                    urls.Add(v.ToString()?.Replace("Route: ", "") ?? "");
                            }

                        }


                    }
                }


                foreach (var path in document.Paths)
                {

                    if (urls.Contains(path.Key))
                    {
                        foreach (var operation in path.Value.Operations)
                        {
                            operation.Value.Security.Add(new OpenApiSecurityRequirement
                            {
                                [new OpenApiSecurityScheme { Reference = new OpenApiReference { Id = "Bearer", Type = ReferenceType.SecurityScheme } }] = Array.Empty<string>()
                            });
                        }
                    }
                }

                //foreach (var operation in document.Paths.Values.SelectMany(path => path.Operations))
                //{

                //    operation.Value.Security.Add(new OpenApiSecurityRequirement
                //    {
                //        [new OpenApiSecurityScheme { Reference = new OpenApiReference { Id = "Bearer", Type = ReferenceType.SecurityScheme } }] = Array.Empty<string>()
                //    });
                //}
            }
        }


    }



}